package com.dynabook.ems.service;

import com.dynabook.ems.mapper.EmsBomDetailMapper;
import com.dynabook.ems.mapper.EmsEngineWorkOrderMapper;
import com.dynabook.ems.mapper.EmsMyBorrowMapper;
import com.dynabook.ems.mapper.EmsWorkOrderMapper;
import com.dynabook.ems.model.entity.EmsBomDetail;
import com.dynabook.ems.model.entity.EmsWorkOrder;
import com.dynabook.ems.model.enums.DetailStatusEnum;
import com.dynabook.ems.model.enums.ModelStatusEnum;
import com.dynabook.ems.model.enums.RedisKeyEnum;
import com.dynabook.ems.model.enums.WorkOrderStatusEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 工单状态同步服务
 * 负责处理工单、详情、申请之间的状态同步逻辑
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WorkOrderStatusSyncService {
    
    private final RedisTemplate<String, Object> redisTemplate;
    private final EmsEngineWorkOrderMapper engineWorkOrderMapper;
    private final EmsMyBorrowMapper myBorrowMapper;
    private final EmsBomDetailMapper bomDetailMapper;
    private final EmsWorkOrderMapper workOrderMapper;
    
    /**
     * 当申请状态变更时调用此方法
     * @param emsRequestId 申请ID
     * @param newStatus 新状态
     */
    @Async("workOrderSyncExecutor")
    public CompletableFuture<Void> onRequestStatusChange(String emsRequestId, Integer newStatus) {
        try {
            log.info("开始处理申请状态变更: emsRequestId={}, newStatus={}", emsRequestId, newStatus);
            
            // 1. 获取申请对应的详情ID
            String detailId = getDetailIdByRequestId(emsRequestId);
            if (detailId == null) {
                log.warn("未找到申请对应的详情ID: emsRequestId={}", emsRequestId);
                return CompletableFuture.completedFuture(null);
            }
            log.info("找到申请对应的详情ID: emsRequestId={}, detailId={}", emsRequestId, detailId);
            
            // 2. 更新Redis中的申请状态
            updateRequestStatusInRedis(detailId, emsRequestId, newStatus);
            log.info("已更新Redis中的申请状态: detailId={}, emsRequestId={}, newStatus={}", detailId, emsRequestId, newStatus);
            
            // 3. 检查该详情下所有申请是否都已同意
            boolean allRequestsApproved = isAllRequestsApproved(detailId);
            log.info("详情下所有申请审批状态检查: detailId={}, allApproved={}", detailId, allRequestsApproved);
            
            if (allRequestsApproved) {
                // 4. 更新详情状态为"已批"
                updateDetailStatusToApproved(detailId);
                log.info("详情状态已更新为已批: detailId={}", detailId);
                
                // 5. 获取工单号并检查工单下所有详情是否都已批
                String workOrderNumber = getWorkOrderNumberByDetailId(detailId);
                log.info("获取到工单号: detailId={}, workOrderNumber={}", detailId, workOrderNumber);
                
                if (workOrderNumber != null) {
                    boolean allDetailsApproved = isAllDetailsApproved(workOrderNumber);
                    log.info("工单下所有详情审批状态检查: workOrderNumber={}, allDetailsApproved={}", workOrderNumber, allDetailsApproved);
                    
                    if (allDetailsApproved) {
                        // 6. 更新工单状态为"INPRODUCTION生产中"
                        log.info("准备更新工单状态为生产中: workOrderNumber={}", workOrderNumber);
                        updateWorkOrderStatusToInProduction(workOrderNumber);
                    } else {
                        log.info("工单下仍有未审批完成的详情，暂不更新工单状态: workOrderNumber={}", workOrderNumber);
                    }
                } else {
                    log.warn("无法获取工单号，跳过工单状态更新: detailId={}", detailId);
                }
            } else {
                log.info("详情下仍有未审批完成的申请，暂不更新详情状态: detailId={}", detailId);
            }
            
            log.info("申请状态变更处理完成: emsRequestId={}", emsRequestId);
            return CompletableFuture.completedFuture(null);
            
        } catch (Exception e) {
            log.error("处理申请状态变更时发生异常: emsRequestId={}, newStatus={}", emsRequestId, newStatus, e);
            throw new RuntimeException("申请状态同步失败", e);
        }
    }
    
    /**
     * 初始化工单的Redis缓存
     * @param workOrderNumber 工单号
     */
    public void initializeWorkOrderCache(String workOrderNumber) {
        try {
            log.info("开始初始化工单缓存: workOrderNumber={}", workOrderNumber);
            
            // 先清理旧的缓存数据，确保重新初始化时使用最新状态
            clearWorkOrderStatusCache(workOrderNumber);
            
            // 查询工单下所有详情
            List<String> detailIds = bomDetailMapper.getDetailIdsByWorkOrder(workOrderNumber);
            
            for (String detailId : detailIds) {
                // 初始化详情到工单的映射
                String mappingKey = RedisKeyEnum.DETAIL_WORKORDER_MAPPING.getKey(detailId);
                redisTemplate.opsForValue().set(mappingKey, workOrderNumber, 60, TimeUnit.DAYS);
                
                // 查询详情下所有申请并初始化状态
                List<Map<String, Object>> requests = engineWorkOrderMapper.getRequestsByDetailId(detailId);
                
                String approvalKey = RedisKeyEnum.DETAIL_APPROVAL_STATUS.getKey(detailId);
                for (Map<String, Object> request : requests) {
                    String emsRequestId = (String) request.get("emsRequestId");
                    // 安全的类型转换：处理 Long 和 Integer 类型
                    Object statusObj = request.get("requestStatus");
                    Integer requestStatus = statusObj != null ? 
                        (statusObj instanceof Integer ? (Integer) statusObj : ((Number) statusObj).intValue()) : null;
                    
                    // 设置申请状态
                    redisTemplate.opsForHash().put(approvalKey, emsRequestId, requestStatus);
                    
                    // 设置申请到详情的映射
                    String requestMappingKey = RedisKeyEnum.REQUEST_DETAIL_MAPPING.getKey(emsRequestId);
                    redisTemplate.opsForValue().set(requestMappingKey, detailId, 60, TimeUnit.DAYS);
                }
                
                // 设置过期时间
                redisTemplate.expire(approvalKey, 60, TimeUnit.DAYS);
                
                // 初始化BOM状态
                String bomStatusKey = RedisKeyEnum.BOM_STATUS_TRACKING.getKey(workOrderNumber);
                Integer detailStatus = bomDetailMapper.getDetailStatusById(detailId);
                redisTemplate.opsForHash().put(bomStatusKey, detailId, detailStatus);
            }
            
            // 设置BOM状态过期时间
            String bomStatusKey = RedisKeyEnum.BOM_STATUS_TRACKING.getKey(workOrderNumber);
            redisTemplate.expire(bomStatusKey, 60, TimeUnit.DAYS);
            
            log.info("工单缓存初始化完成: workOrderNumber={}", workOrderNumber);
            
        } catch (Exception e) {
            log.error("初始化工单缓存时发生异常: workOrderNumber={}", workOrderNumber, e);
            throw new RuntimeException("工单缓存初始化失败", e);
        }
    }
    
    /**
     * 清理工单状态相关的Redis缓存
     */
    private void clearWorkOrderStatusCache(String workOrderNumber) {
        log.info("开始清理工单状态缓存: workOrderNumber={}", workOrderNumber);
        
        String bomStatusKey = RedisKeyEnum.BOM_STATUS_TRACKING.getKey(workOrderNumber);
        redisTemplate.delete(bomStatusKey);
        log.info("已清理BOM状态跟踪缓存: key={}", bomStatusKey);

        // 清理详情到工单的映射
        List<String> detailIds = bomDetailMapper.getDetailIdsByWorkOrder(workOrderNumber);
        log.info("找到详情ID列表: workOrderNumber={}, detailIds={}", workOrderNumber, detailIds);
        
        for (String detailId : detailIds) {
            String detailMappingKey = RedisKeyEnum.DETAIL_WORKORDER_MAPPING.getKey(detailId);
            redisTemplate.delete(detailMappingKey);
            log.debug("已清理详情映射缓存: key={}", detailMappingKey);
        }

        // 清理申请到详情的映射
        int totalRequestsCleaned = 0;
        for (String detailId : detailIds) {
            String approvalKey = RedisKeyEnum.DETAIL_APPROVAL_STATUS.getKey(detailId);
            Map<Object, Object> requests = redisTemplate.opsForHash().entries(approvalKey);
            log.debug("详情审批状态缓存: detailId={}, requestCount={}", detailId, requests.size());
            
            for (Map.Entry<Object, Object> entry : requests.entrySet()) {
                String emsRequestId = (String) entry.getKey();
                String requestMappingKey = RedisKeyEnum.REQUEST_DETAIL_MAPPING.getKey(emsRequestId);
                redisTemplate.delete(requestMappingKey);
                totalRequestsCleaned++;
                log.debug("已清理申请映射缓存: key={}", requestMappingKey);
            }
            redisTemplate.delete(approvalKey);
            log.debug("已清理详情审批状态缓存: key={}", approvalKey);
        }
        
        log.info("工单状态缓存清理完成: workOrderNumber={}, detailCount={}, requestCount={}", 
            workOrderNumber, detailIds.size(), totalRequestsCleaned);
    }
    
    /**
     * 根据申请ID获取详情ID
     */
    private String getDetailIdByRequestId(String emsRequestId) {
        String mappingKey = RedisKeyEnum.REQUEST_DETAIL_MAPPING.getKey(emsRequestId);
        Object detailId = redisTemplate.opsForValue().get(mappingKey);
        
        if (detailId == null) {
            // 从数据库查询
            detailId = engineWorkOrderMapper.getDetailIdByRequestId(emsRequestId);
            if (detailId != null) {
                redisTemplate.opsForValue().set(mappingKey, detailId, 60, TimeUnit.DAYS);
            }
        }
        
        return detailId != null ? detailId.toString() : null;
    }
    
    /**
     * 更新Redis中的申请状态
     */
    private void updateRequestStatusInRedis(String detailId, String emsRequestId, Integer newStatus) {
        String approvalKey = RedisKeyEnum.DETAIL_APPROVAL_STATUS.getKey(detailId);
        redisTemplate.opsForHash().put(approvalKey, emsRequestId, newStatus);
        redisTemplate.expire(approvalKey, 60, TimeUnit.DAYS);
    }
    
    /**
     * 检查详情下所有申请是否都已同意
     */
    private boolean isAllRequestsApproved(String detailId) {
        String approvalKey = RedisKeyEnum.DETAIL_APPROVAL_STATUS.getKey(detailId);
        Map<Object, Object> requestStatuses = redisTemplate.opsForHash().entries(approvalKey);
        
        if (requestStatuses.isEmpty()) {
            return false;
        }
        
        // 检查所有申请状态是否为已审批(3)或待分配(13)
        return requestStatuses.values().stream()
                .allMatch(status -> {
                    Integer statusValue = (Integer) status;
                    return ModelStatusEnum.USING.getValue().equals(statusValue) || 
                           ModelStatusEnum.PART_USING.getValue().equals(statusValue);
                });
    }
    
    /**
     * 更新详情状态为已批
     */
    @Transactional
    public void updateDetailStatusToApproved(String detailId) {
        try {
            // 获取分布式锁
            String lockKey = RedisKeyEnum.WORK_ORDER_LOCK.getKey("detail_" + detailId);
            Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 30, TimeUnit.SECONDS);
            
            if (!Boolean.TRUE.equals(lockAcquired)) {
                log.warn("获取详情状态更新锁失败: detailId={}", detailId);
                return;
            }
            
            try {
                // 更新数据库
                EmsBomDetail bomDetail = new EmsBomDetail();
                bomDetail.setId(Long.parseLong(detailId));
                bomDetail.setDetailStatus(DetailStatusEnum.APPROVED.getValue());
                bomDetailMapper.updateById(bomDetail);
                
                // 更新Redis缓存
                String workOrderNumber = getWorkOrderNumberByDetailId(detailId);
                if (workOrderNumber != null) {
                    String bomStatusKey = RedisKeyEnum.BOM_STATUS_TRACKING.getKey(workOrderNumber);
                    redisTemplate.opsForHash().put(bomStatusKey, detailId, DetailStatusEnum.APPROVED.getValue());
                }
                
                log.info("详情状态已更新为已批: detailId={}", detailId);
                
            } finally {
                // 释放锁
                redisTemplate.delete(lockKey);
            }
            
        } catch (Exception e) {
            log.error("更新详情状态时发生异常: detailId={}", detailId, e);
            throw new RuntimeException("更新详情状态失败", e);
        }
    }
    
    /**
     * 根据详情ID获取工单号
     */
    private String getWorkOrderNumberByDetailId(String detailId) {
        String mappingKey = RedisKeyEnum.DETAIL_WORKORDER_MAPPING.getKey(detailId);
        Object workOrderNumber = redisTemplate.opsForValue().get(mappingKey);
        
        if (workOrderNumber == null) {
            // 从数据库查询
            workOrderNumber = bomDetailMapper.getWorkOrderNumberByDetailId(detailId);
            if (workOrderNumber != null) {
                redisTemplate.opsForValue().set(mappingKey, workOrderNumber, 60, TimeUnit.DAYS);
            }
        }
        
        return workOrderNumber != null ? workOrderNumber.toString() : null;
    }
    
    /**
     * 检查工单下所有详情是否都已批
     */
    private boolean isAllDetailsApproved(String workOrderNumber) {
        String bomStatusKey = RedisKeyEnum.BOM_STATUS_TRACKING.getKey(workOrderNumber);
        Map<Object, Object> detailStatuses = redisTemplate.opsForHash().entries(bomStatusKey);
        
        if (detailStatuses.isEmpty()) {
            return false;
        }
        return detailStatuses.values().stream()
                .allMatch(status -> {
                    Integer statusValue = (Integer) status;
                    return DetailStatusEnum.APPROVED.getValue().equals(statusValue) ||
                            DetailStatusEnum.MODIFICATION.getValue().equals(statusValue);
                });
    }
    
    /**
     * 更新工单状态为生产中
     */
    @Transactional
    public void updateWorkOrderStatusToInProduction(String workOrderNumber) {
        try {
            log.info("开始更新工单状态为生产中: workOrderNumber={}", workOrderNumber);

            // 获取分布式锁
            String lockKey = RedisKeyEnum.WORK_ORDER_LOCK.getKey(workOrderNumber);
            Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 30, TimeUnit.SECONDS);
            
            if (!Boolean.TRUE.equals(lockAcquired)) {
                log.warn("获取工单状态更新锁失败: workOrderNumber={}", workOrderNumber);
                return;
            }
            
            try {
                // 更新数据库
                EmsWorkOrder workOrder = new EmsWorkOrder();
                workOrder.setWorkOrderNum(workOrderNumber);
                workOrder.setWorkOrderStatus(WorkOrderStatusEnum.INPRODUCTION.getValue());
                workOrder.setReason("系统自动更新：所有详情已通过审批");
                int updated = workOrderMapper.updateByWorkOrderNum(workOrder);
                
                log.info("工单状态更新结果: workOrderNumber={}, updated={}, newStatus={}", 
                    workOrderNumber, updated, WorkOrderStatusEnum.INPRODUCTION.getText());
                
                if (updated == 0) {
                    log.warn("工单状态更新失败，可能工单不存在: workOrderNumber={}", workOrderNumber);
                }
                
            } finally {
                // 释放锁
                redisTemplate.delete(lockKey);
            }
            
        } catch (Exception e) {
            log.error("更新工单状态时发生异常: workOrderNumber={}", workOrderNumber, e);
            throw new RuntimeException("更新工单状态失败", e);
        }
    }
}